package com.kinyx.framework.image;

import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.imageio.ImageIO;

import com.kinyx.framework.Configs;
import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.Throws;
import com.kinyx.framework.enums.impl.ErrorCodeX;
import com.kinyx.framework.exception.KRuntimeException;
import com.kinyx.framework.file.KFileReader;
import com.kinyx.framework.file.KFileUtils;
import com.kinyx.framework.security.KBASE64;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 图片工具类
 */
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public final class KImageUtils {

	/**
	 * 读取图片
	 * @param imageFile 图片文件对象
	 * @return 图片对象
	 */
	@ReturnNotNull
	@Throws(at = "KFileUtils.checkFile(File)", value = "ErrorCode0.FileDoesNotExists", when = "!File.exists()")
	@Throws(at = "KFileUtils.checkFile(File)", value = "ErrorCode0.IsNotAFile", when = "!File.isFile()")
	@Throws(at = "KImageUtils.read(File)", value = "IOException", when = "ImageIO.read(File)")
	public static BufferedImage readBufferedImage(@CanNotNull final File imageFile) {
		KFileUtils.checkFile(imageFile);
		try {
			return ImageIO.read(imageFile);
		} catch (final IOException e) {
			throw new KRuntimeException(e);
		}
	}

	/**
	 * 读取图片
	 * @param imageFile 图片文件对象
	 * @return 字节数组
	 */
	@ReturnNotNull
	@Throws(at = "KReader.readBytes(InputStream)", value = "IOException", when = "InputStream.available()")
	@Throws(at = "KReader.readBytes(InputStream)", value = "IOException", when = "InputStream.read(byte[])")
	@Throws(at = "KFileUtils.checkFile(File)", value = "ErrorCode0.FileDoesNotExists", when = "!File.exists()")
	@Throws(at = "KFileUtils.checkFile(File)", value = "ErrorCode0.IsNotAFile", when = "!File.isFile()")
	@Throws(at = "KFileUtils.checkReadable(File)", value = "ErrorCode0.FileIsNotReadable", when = "!File.canRead()")
	//	@Throws(at = "KFileReader.newFileInputStream(File)", value = "FileNotFoundException", when = "new FileInputStream(File)")
	public static byte[] readBytes(@CanNotNull final File imageFile) {
		return KFileReader.readBytes(imageFile);
	}

	/**
	 * 读取图片
	 * @param imageFile 图片文件对象
	 * @param charset 字符集
	 * @return 图片对象
	 */
	@ReturnNotNull
	@Throws(at = "KBase64.encode(byte[], String)", value = "UnsupportedEncodingException", when = "new String(byte[], String)")
	@Throws(at = "KReader.readBytes(InputStream)", value = "IOException", when = "InputStream.available()")
	@Throws(at = "KReader.readBytes(InputStream)", value = "IOException", when = "InputStream.read(byte[])")
	@Throws(at = "KFileUtils.checkFile(File)", value = "ErrorCode0.FileDoesNotExists", when = "!File.exists()")
	@Throws(at = "KFileUtils.checkFile(File)", value = "ErrorCode0.IsNotAFile", when = "!File.isFile()")
	@Throws(at = "KFileUtils.checkReadable(File)", value = "ErrorCode0.FileIsNotReadable", when = "!File.canRead()")
	//	@Throws(at = "KFileReader.newFileInputStream(File)", value = "FileNotFoundException", when = "new FileInputStream(File)")
	public static String readBASE64(@CanNotNull final File imageFile, @CanNull(defaultValue = "Configs.default_KImageUtils_charset") final String charset) {
		if (charset == null) { return readBASE64(imageFile, Configs.default_KImageUtils_charset); }
		return KBASE64.encode(readBytes(imageFile), charset);
	}

	/**
	 * 写入图片
	 * @param imagePath 图片路径（全路径）
	 * @param image 图片对象
	 */
	@Throws(at = "KFileUtils.checkDirectory(File, boolean)", value = "ErrorCode0.IsNotADirectory", when = "!File.isDirectory()")
	@Throws(at = "KFileUtils.createNewFile(String)", value = "IOException", when = "File.createNewFile()")
	@Throws(at = "KFileUtils.checkWriteable(File)", value = "ErrorCode0.FileIsNotWriteable", when = "!File.canWrite()")
	@Throws(at = "KImageUtils.write(String, RenderedImage)", value = "IOException", when = "ImageIO.write(RenderedImage, String, File)")
	public static void write(@CanNotNull final String imagePath, @CanNotNull final RenderedImage image) {
		final File file = KFileUtils.createNewFile(imagePath);
		KFileUtils.checkWriteable(file);
		try {
			ImageIO.write(image, KFileUtils.getExtension(imagePath).substring(1), file);
		} catch (final IOException e) {
			throw new KRuntimeException(e);
		}
	}

	/**
	 * 写入图片
	 * @param imagePath 图片路径（全路径）
	 * @param bytes 字节码
	 */
	@Throws(at = "KFileUtils.checkDirectory(File, boolean)", value = "ErrorCode0.IsNotADirectory", when = "!File.isDirectory()")
	@Throws(at = "KFileUtils.createNewFile(String)", value = "IOException", when = "File.createNewFile()")
	@Throws(at = "KFileUtils.checkWriteable(File)", value = "ErrorCode0.FileIsNotWriteable", when = "!File.canWrite()")
	//	@Throws(at = "KImageUtils.write(String, byte[])", value = "FileNotFoundException", when = "new FileOutputStream(File)")
	@Throws(at = "KImageUtils.write(String, byte[])", value = "IOException", when = "OutputStream.write(byte[])")
	public static void write(@CanNotNull final String imagePath, @CanNotNull final byte[] bytes) {
		final File file = KFileUtils.createNewFile(imagePath);
		KFileUtils.checkWriteable(file);
		OutputStream os;
		try {
			os = new FileOutputStream(file);
		} catch (final FileNotFoundException e) {
			throw new KRuntimeException(e, ErrorCodeX.NeverHappens);
		}
		try {
			os.write(bytes);
		} catch (final IOException e) {
			throw new KRuntimeException(e);
		} finally {
			if (os != null) {
				try {
					os.close();
				} catch (final Exception e) {} // ignore this
			}
		}
	}

	/**
	 * 写入图片
	 * @param imagePath 图片路径（全路径）
	 * @param base64 BASE64字符串
	 */
	@Throws(at = "KFileUtils.checkDirectory(File, boolean)", value = "ErrorCode0.IsNotADirectory", when = "!File.isDirectory()")
	@Throws(at = "KFileUtils.createNewFile(String)", value = "IOException", when = "File.createNewFile()")
	@Throws(at = "KFileUtils.checkWriteable(File)", value = "ErrorCode0.FileIsNotWriteable", when = "!File.canWrite()")
	//	@Throws(at = "KImageUtils.write(String, byte[])", value = "FileNotFoundException", when = "new FileOutputStream(File)")
	@Throws(at = "KImageUtils.write(String, byte[])", value = "IOException", when = "OutputStream.write(byte[])")
	public static void write(@CanNotNull final String imagePath, @CanNotNull final String base64) {
		write(imagePath, KBASE64.decode(base64));
	}

}
